package com.zong.ai.agent.app;

import com.zong.ai.agent.advisor.MyLoggerAdvisor;
import com.zong.ai.agent.advisor.SensitiveWordAdvisor;
import com.zong.ai.agent.chatMemory.InFileChatMemory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.chat.client.advisor.RetrievalAugmentationAdvisor;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.rag.retrieval.search.DocumentRetriever;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;
import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY;

/**
 * @author: zongzi
 * @description: 游戏王应用
 * @date: 2025/6/15
 */
@Component
public class YouGiApp {
    @Value("${prompts-template.card-answer}")
    private Resource cardAnswerPromptsTemplate;

    private static final String YOU_GI_SYSTEM_PROMPT = "# 角色\n" +
            "你是一位游戏王高手，精通各种游戏王的规则和策略。你拥有丰富的卡牌知识和实战经验，能够为玩家提供专业的卡牌建议和战术指导。\n" +
            "\n" +
            "## 技能\n" +
            "### 技能1：理解并解释规则\n" +
            "- 熟悉并解释游戏王的各种规则，包括基本规则、高级规则以及最新的规则更新。\n" +
            "- 解答玩家关于规则的疑问，确保他们对游戏机制有清晰的理解。\n" +
            "\n" +
            "### 技能2：提供卡牌建议\n" +
            "- 根据玩家的需求（如构筑特定类型的卡组、针对特定对手等），推荐合适的卡牌。\n" +
            "- 分析卡牌的效果和适用场景，帮助玩家构建强大的卡组。\n" +
            "\n" +
            "### 技能3：战术指导\n" +
            "- 提供战术建议，帮助玩家在比赛中制定有效的策略。\n" +
            "- 分析对手的卡组和战术，提出应对措施和改进方案。\n" +
            "\n" +
            "### 技能4：卡组优化\n" +
            "- 评估玩家现有的卡组，提出优化建议，提升卡组的整体性能。\n" +
            "- 根据当前的游戏环境和流行趋势，调整卡组以适应新的挑战。\n" +
            "\n" +
            "## 限制条件：\n" +
            "- 仅讨论与游戏王相关的主题，不涉及其他游戏或无关话题。\n" +
            "- 始终基于官方规则和最新信息提供建议，避免传播错误信息。\n" +
            "- 尊重玩家的选择和偏好，提供多种可行方案供玩家参考。\n" +
            "- 不泄露未公开的卡牌信息或比赛策略，确保公平竞争。";

    private final ChatClient chatClient;
    private final ChatModel dashScopeChatModel;

    public YouGiApp(ChatModel dashScopeChatModel) {
        this.dashScopeChatModel = dashScopeChatModel;
        // 基于内存的会话记忆
        InMemoryChatMemory memory = new InMemoryChatMemory();
        chatClient = ChatClient.builder(dashScopeChatModel)
                .defaultSystem(YOU_GI_SYSTEM_PROMPT)
                // 添加会话记忆的拦截器
                .defaultAdvisors(
                        new MessageChatMemoryAdvisor(memory),
                        new MyLoggerAdvisor(),
                        new SensitiveWordAdvisor("作弊", "开挂")
                )
                .build();
    }

    public String chat(String usrMessage, String chatId) {
        return chatClient.prompt()
                .user(usrMessage)
                // 会话记忆参数
                .advisors(advisorSpec -> {
                    advisorSpec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId);
                    advisorSpec.param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10);
                })
                .call()
                .content();
    }

    public <T> T doChatWithStructured(String usrMessage, Class<T> beanClass) {
        return chatClient.prompt()
                .user(usrMessage)
                .call()
                .entity(beanClass);
    }

    public String doChatWithInFileChatMemory(String usrMessage, String chatId) {
        // 基于内存的会话记忆
        InFileChatMemory memory = new InFileChatMemory();
        ChatClient client = ChatClient.builder(dashScopeChatModel)
                .defaultSystem(YOU_GI_SYSTEM_PROMPT)
                // 添加会话记忆的拦截器
                .defaultAdvisors(
                        new MessageChatMemoryAdvisor(memory),
                        new MyLoggerAdvisor(),
                        new SensitiveWordAdvisor("作弊", "开挂")
                ).build();

        ChatResponse chatResponse = client.prompt()
                .user(usrMessage)
                // 会话记忆参数
                .advisors(advisorSpec -> {
                    advisorSpec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId);
                    advisorSpec.param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10);
                })
                .call()
                .chatResponse();
        return chatResponse.getResult().getOutput().getText();
    }

    public String doChatWithPromptTemplate(String cardName, String cardType) {
        ChatClient client = ChatClient.builder(dashScopeChatModel).build();
        Map<String, Object> params = new HashMap<>();
        params.put("cardName", cardName);
        params.put("cardType", cardType);
        ChatResponse chatResponse = client.prompt().user(u -> u.text(cardAnswerPromptsTemplate).params(params)).call().chatResponse();
        return chatResponse.getResult().getOutput().getText();
    }

    public String doChatWithRag(String userMessage, String chatId, VectorStore vectorStore) {
        ChatResponse chatResponse = chatClient.prompt()
                .user(userMessage)
                .advisors(new QuestionAnswerAdvisor(vectorStore))
                // 会话记忆参数
                .advisors(advisorSpec -> {
                    advisorSpec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId);
                    advisorSpec.param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10);
                })
                .call()
                .chatResponse();
        return chatResponse.getResult().getOutput().getText();
    }

    public String doChatWithBaiLianRag(String userMessage, String chatId, DocumentRetriever documentRetriever) {
        ChatResponse chatResponse = chatClient.prompt()
                .user(userMessage)
                // 检索增强 advisor
                .advisors(RetrievalAugmentationAdvisor.builder()
                        .documentRetriever(documentRetriever)
                        .build())
                // 会话记忆参数
                .advisors(advisorSpec -> {
                    advisorSpec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId);
                    advisorSpec.param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10);
                })
                .call()
                .chatResponse();
        return chatResponse.getResult().getOutput().getText();
    }
}
